using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.VisualStudio.Modeling.Validation;
using Microsoft.VisualStudio.Modeling;

namespace Evaluant.EussDSL
{
    [ValidationState(ValidationState.Enabled)]
    public partial class ModelAttribute
    {
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="store">Store where new element is to be created.</param>
        /// <param name="propertyAssignments">List of domain property id/value pairs to set once the element is created.</param>
        public ModelAttribute(Store store, params PropertyAssignment[] propertyAssignments)
            : this(store != null ? store.DefaultPartition : null, propertyAssignments)
        {
            if (string.IsNullOrEmpty(dbtype))
            {
                dbtype = "String";
            }
        }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="partition">Partition where new element is to be created.</param>
        /// <param name="propertyAssignments">List of domain property id/value pairs to set once the element is created.</param>
        public ModelAttribute(Partition partition, params PropertyAssignment[] propertyAssignments)
            : base(partition, propertyAssignments)
        {
            if (string.IsNullOrEmpty(dbtype))
            {
                dbtype = "String";
            }
        }

        internal sealed partial class namePropertyHandler
        {
            protected override void OnValueChanged(ModelAttribute element, string oldValue, string newValue)
            {
                if (!element.Store.InUndoRedoOrRollback)
                {
                    if (string.IsNullOrEmpty(newValue))
                    {
                        throw new ArgumentOutOfRangeException("Name", "Name cannot be empty or null.");
                    }
                }
                base.OnValueChanged(element, oldValue, newValue);
            }
        }

        internal sealed partial class dbtypePropertyHandler
        {
            protected override void OnValueChanged(ModelAttribute element, string oldValue, string newValue)
            {
                if (!element.Store.InUndoRedoOrRollback)
                {
                    if (string.IsNullOrEmpty(newValue))
                    {
                        throw new ArgumentOutOfRangeException("dbtype", "dbtype cannot be empty or null.");
                    }
                }
                base.OnValueChanged(element, oldValue, newValue);
            }
        }

        [ValidationMethod(ValidationCategories.Menu | ValidationCategories.Save)]
        private void ValidSize(ValidationContext context)
        {
            int res;
            bool success = int.TryParse(size, out res);
            if (!string.IsNullOrEmpty(size) && !success)
            {
                context.LogError("The 'size' value of the Attribute '" + name + "' of the Entity '" + this.Entity.type + "' is not an Integer.", "014", this.Entity);
            }
            if (success && res <= 0)
            {
                context.LogError("The 'size' value of the Attribute '" + name + "' of the Entity '" + this.Entity.type + "' is not a positive Integer.", "014", this.Entity);
            }
        }

        [ValidationMethod(ValidationCategories.Menu | ValidationCategories.Save)]
        private void ValidScale(ValidationContext context)
        {
            int res;
            bool success = int.TryParse(scale, out res);
            if (!string.IsNullOrEmpty(scale) && !success)
            {
                context.LogError("The 'scale' value of the Attribute '" + name + "' of the Entity '" + this.Entity.type + "' is not an Integer.", "015", this.Entity);
            }
            if (success && res <= 0)
            {
                context.LogError("The 'scale' value of the Attribute '" + name + "' of the Entity '" + this.Entity.type + "' is not a positive Integer.", "015", this.Entity);
            }
        }

        [ValidationMethod(ValidationCategories.Menu | ValidationCategories.Save)]
        private void ValidPrecision(ValidationContext context)
        {
            int res;
            bool success = int.TryParse(precision, out res);
            if (!string.IsNullOrEmpty(precision) && !success)
            {
                context.LogError("The 'precision' value of the Attribute '" + name + "' of the Entity '" + this.Entity.type + "' is not an Integer.", "016", this.Entity);
            }
            if (success && res <= 0)
            {
                context.LogError("The 'precision' value of the Attribute '" + name + "' of the Entity '" + this.Entity.type + "' is not a positive Integer.", "016", this.Entity);
            }
        }

        [ValidationMethod(ValidationCategories.Menu | ValidationCategories.Save)]
        private void ValidNotNull(ValidationContext context)
        {
            if (!string.IsNullOrEmpty(notnull) && notnull != "true" && notnull != "false")
            {
                context.LogError("The 'NotNull' value of the Attribute '" + name + "' of the Entity '" + this.Entity.type + "' must be Boolean and must match either 'true' or 'false'.", "017", this.Entity);
            }
        }

        [ValidationMethod(ValidationCategories.Menu | ValidationCategories.Save)]
        private void TableExists(ValidationContext context)
        {
            if (!string.IsNullOrEmpty(table) && Entity.EussMapping.Elements.FindAll(delegate(Entity en){ return en.table == table;}).Count> 0)
            {
                context.LogError("The 'table' value of the attribute '" + name + "' of the entity '" + Entity.type + "' doesn't match a 'table' value of an Entity in the mapping file.", "020", this.Entity);
            }
        }

        [ValidationMethod(ValidationCategories.Menu | ValidationCategories.Save)]
        private void ParentFieldAndTable(ValidationContext context)
        {
            if (!string.IsNullOrEmpty(parentField) && string.IsNullOrEmpty(table))
            {
                context.LogWarning("There is a 'parentField' value of the attribute '" + name + "' of the entity '" + Entity.type + "' but this Attribute doesn't contain a 'table' value. Consequently, the 'parentField' will be ignored.", "021", this.Entity);
            }
        }

        [ValidationMethod(ValidationCategories.Menu | ValidationCategories.Save)]
        private void ParentFieldAndField(ValidationContext context)
        {
            if (!string.IsNullOrEmpty(parentField) && !string.IsNullOrEmpty(field))
            {
                context.LogError("There shouldn't be a value for both 'parentField' and 'field' in the attribute '" + name + "' of the entity '" + Entity.type + "'.", "022", this.Entity);
            }
        }

        [ValidationMethod(ValidationCategories.Menu | ValidationCategories.Save)]
        private void DefaultValueAndNotNull(ValidationContext context)
        {
            if (!string.IsNullOrEmpty(defaultValue) && notnull != "true")
            {
                context.LogError("A 'defaultValue' value of the attribute '" + name + "' of the entity '" + Entity.type + "' can be set only if 'notnull' is 'true'.", "023", this.Entity);
            }
        }
    }
}
